package com.yuanmei.common;

//import android.content.Context;
//import android.content.pm.ApplicationInfo;

import android.os.Looper;
import android.util.Log;

import com.github.promeg.pinyinhelper.Pinyin;
import com.yuanmei.datas.PyTdxHistory;
import com.yuanmei.git_lite.GitHelper;
import com.yuanmei.model.HistoryHourQuote;
import com.yuanmei.model.HistoryMonthQuote;
import com.yuanmei.model.HistoryWeekQuote;
import com.yuanmei.model.KLineChartQuote;
import com.yuanmei.model.TickQuote;
import com.yuanmei.model.TradeCalenderRealm;
import com.yuanmei.views.QuickStockApplication;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;
import io.realm.Sort;


public class Utils {
    public static final String TAG = "Utils";

//    private static final BigDecimal HUNDRED = new BigDecimal(100);
//    private static final BigDecimal THOUSAND = new BigDecimal(1000);
//    private static final BigDecimal MILLION = new BigDecimal(1000000);
//    private static final BigDecimal BILLION = new BigDecimal(1000000000);

    public final static String SP_CONFIG_FILE = "TuViewConfig";
    public final static String SP_STOCK_INFO_UPDATE_KEY = "StockInfoUpdateTimeStamp";
    public final static String SP_STOCK_BASICS_UPDAT_KEY = "StockBasicsUpdateTimeStamp";

    public final static String CONTENT_TYPE = "text/html; charset=UTF-8";
    public final static String HTTP_AGENT =
            "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36";

    public static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
    public static final long MILLIS_PER_HOUR = 60 * 60 * 1000;
    public static final int TRADE_HOUR_PER_DAY = 4;
    public static final int TRADE_SECONDS_FULL_DAY = 4 * 60 * 60;
    public static final int TRADE_SECONDS_HALF_DAY = 2 * 60 * 60;
    public static final int SECONDS_PER_HOUR = 60 * 60;

    public final static SimpleDateFormat sDefaultDateFormat
            = new SimpleDateFormat("yyyyMMdd", Locale.CHINA);
    public final static SimpleDateFormat sHyphenDateFormat
            = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
    public final static SimpleDateFormat sDateMinuteFormat
            = new SimpleDateFormat("yyyyMMddHHmm", Locale.CHINA);


//    private static String join(String[] data, String d) {
//        if (data.length == 0) {
//            return "";
//        }
//        StringBuilder sb = new StringBuilder();
//        int i;
//
//        for (i = 0; i < (data.length - 1); i++) {
//            sb.append(data[i]).append(d);
//        }
//        return sb.append(data[i]).toString();
//    }

//    private static String cleanNumberString(String data) {
//        return Utils.join(data.trim().split(","), "");
//    }

    private static boolean isInvalidNumberString(String data) {
        if (data == null)
            return true;
        return (data.equals("None") || data.equals("-") || data.equals(""));
    }

//    private static BigDecimal getBigDecimal(String data) {
//        BigDecimal result = BigDecimal.ZERO;
//        if (Utils.isInvalidNumberString(data)) {
//            return result;
//        }
//        try {
//            data = Utils.cleanNumberString(data);
//            char lastChar = data.charAt(data.length() - 1);
//            BigDecimal multiplier = BigDecimal.ONE;
//            switch (lastChar) {
//                case 'B':
//                    data = data.substring(0, data.length() - 1);
//                    multiplier = BILLION;
//                    break;
//                case 'M':
//                    data = data.substring(0, data.length() - 1);
//                    multiplier = MILLION;
//                    break;
//                case 'K':
//                    data = data.substring(0, data.length() - 1);
//                    multiplier = THOUSAND;
//                    break;
//            }
//            result = new BigDecimal(data).multiply(multiplier);
//        } catch (NumberFormatException e) {
//            Log.e(TAG, "Failed to parse: " + data, e);
//        }
//        return result;
//    }

//    public static BigDecimal getBigDecimal(String dataMain, String dataSub) {
//        BigDecimal main = getBigDecimal(dataMain);
//        BigDecimal sub = getBigDecimal(dataSub);
//        if(main.compareTo(BigDecimal.ZERO) == 0) {
//            return sub;
//        }
//        return main;
//    }

//    public static double getDouble(String data) {
//        double result = 0.00;
//        if (Utils.isInvalidNumberString(data)) {
//            return result;
//        }
//        try {
//            data = Utils.cleanNumberString(data);
//            char lastChar = data.charAt(data.length() - 1);
//            int multiplier = 1;
//            switch (lastChar) {
//                case 'B':
//                    data = data.substring(0, data.length() - 1);
//                    multiplier = 1000000000;
//                    break;
//                case 'M':
//                    data = data.substring(0, data.length() - 1);
//                    multiplier = 1000000;
//                    break;
//                case 'K':
//                    data = data.substring(0, data.length() - 1);
//                    multiplier = 1000;
//                    break;
//            }
//            result = Double.parseDouble(data) * multiplier;
//        } catch (NumberFormatException e) {
//            Log.e(TAG,"Failed to parse: " + data, e);
//        }
//        return result;
//    }


//    public static int getInt(String data) {
//        int result = 0;
//        if (Utils.isInvalidNumberString(data)) {
//            return result;
//        }
//        try {
//            data = Utils.cleanNumberString(data);
//            result = Integer.parseInt(data);
//        } catch (NumberFormatException e) {
//            Log.e(TAG, "Failed to parse: " + data, e);
//        }
//        return result;
//    }

//    public static long getLong(String data) {
//        long result = 0;
//        if (Utils.isInvalidNumberString(data)) {
//            return result;
//        }
//        try {
//            data = Utils.cleanNumberString(data);
//            result = Long.parseLong(data);
//        } catch (NumberFormatException e) {
//            Log.e(TAG, "Failed to parse: " + data, e);
//        }
//        return result;
//    }
//
//    public static BigDecimal getPercent(BigDecimal numerator, BigDecimal denominator) {
//        if (denominator.compareTo(BigDecimal.ZERO) == 0) {
//            return BigDecimal.ZERO;
//        }
//        return numerator.divide(denominator, 4, BigDecimal.ROUND_HALF_EVEN)
//                .multiply(HUNDRED).setScale(2, BigDecimal.ROUND_HALF_EVEN);
//    }
//
//    public static double getPercent(double numerator, double denominator) {
//        if (denominator == 0) {
//            return 0;
//        }
//        return (numerator / denominator) * 100;
//    }
//
//    private static String getDividendDateFormat(String date) {
//        if (date.matches("[0-9][0-9]-...-[0-9][0-9]")) {
//            return "dd-MMM-yy";
//        } else if (date.matches("[0-9]-...-[0-9][0-9]")) {
//            return "d-MMM-yy";
//        } else if (date.matches("...[ ]+[0-9]+")) {
//            return "MMM d";
//        } else {
//            return "M/d/yy";
//        }
//    }
//
//    /**
//     * Used to parse the dividend dates. Returns null if the keyDate cannot be
//     * parsed.
//     *
//     * @param date String received that represents the keyDate
//     * @return Calendar object representing the parsed keyDate
//     */
//    public static Calendar parseDividendDate(String date) {
//        if (Utils.isInvalidNumberString(date)) {
//            return null;
//        }
//        date = date.trim();
//        SimpleDateFormat format = new SimpleDateFormat(Utils.getDividendDateFormat(date), Locale.US);
//        format.setTimeZone(TimeZone.getTimeZone(Utils.TIMEZONE));
//        try {
//            Calendar today = Calendar.getInstance(TimeZone.getTimeZone(Utils.TIMEZONE));
//            Calendar parsedDate = Calendar.getInstance(TimeZone.getTimeZone(Utils.TIMEZONE));
//            parsedDate.setTime(format.parse(date));
//
//            if (parsedDate.get(Calendar.YEAR) == 1970) {
//                // Not really clear which year the dividend keyDate is... making a reasonable guess.
//                int monthDiff = parsedDate.get(Calendar.MONTH) - today.get(Calendar.MONTH);
//                int year = today.get(Calendar.YEAR);
//                if (monthDiff > 6) {
//                    year -= 1;
//                } else if (monthDiff < -6) {
//                    year += 1;
//                }
//                parsedDate.set(Calendar.YEAR, year);
//            }
//
//            return parsedDate;
//        } catch (ParseException ex) {
//            Log.e(TAG, ex.getMessage(), ex);
//            return null;
//        }
//    }

//    /**
//     * Used to parse the last trade keyDate / time. Returns null if the keyDate / time
//     * cannot be parsed.
//     *
//     * @param date String received that represents the keyDate
//     * @param time String received that represents the time
//     * @return Calendar object with the parsed datetime
//     */
//    public static Calendar parseDateTime(String date, String time) {
//        String datetime = date + " " + time;
//        SimpleDateFormat format = new SimpleDateFormat("M/d/yyyy h:mma", Locale.US);
//        format.setTimeZone(TimeZone.getTimeZone(Utils.TIMEZONE));
//        try {
//            if (!Utils.isInvalidNumberString(date) && !Utils.isInvalidNumberString(time)) {
//                Calendar c = Calendar.getInstance();
//                c.setTime(format.parse(datetime));
//                return c;
//            }
//        } catch (ParseException ex) {
//            Log.e(TAG, ex.getMessage(), ex);
//        }
//        return null;
//    }

    public static int parseTuShareFormatDate(String date) {
        String[] dateArray = date.split("-");
        return Integer.valueOf(dateArray[0]) * 100 * 100
                + Integer.valueOf(dateArray[1]) * 100
                + Integer.valueOf(dateArray[2]);
    }

    public static int parseTTDateStringToIDate(String date) {
        String[] dateArray = date.split("-");
        return Integer.valueOf(dateArray[0]) * 100 * 100
                + Integer.valueOf(dateArray[1]) * 100
                + Integer.valueOf(dateArray[2]);
    }

    @SuppressWarnings("deprecation")
    public static Date getDateFromIDate(int iDate) {
        int year = iDate / 100 / 100;
        int month = (iDate - year * 100 * 100) / 100;
        int day = iDate - year * 100 * 100 - month * 100;
        return new Date(year - 1900, month - 1, day, 17, 0, 0);
    }

    public static String getWeekDay(Date dt) {
        Calendar cal = Calendar.getInstance(Locale.CHINA);
        cal.setTime(dt);
        // Sunday - Saturday: from 1 - 7
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        String cnWeekDay = "";
        switch (dayOfWeek) {
            case 1:
                cnWeekDay = "日";
                break;
            case 2:
                cnWeekDay = "一";
                break;
            case 3:
                cnWeekDay = "二";
                break;
            case 4:
                cnWeekDay = "三";
                break;
            case 5:
                cnWeekDay = "四";
                break;
            case 6:
                cnWeekDay = "五";
                break;
            case 7:
                cnWeekDay = "六";
                break;
            default:
                break;
        }

        return cnWeekDay;
    }

    @SuppressWarnings("deprecation")
    public static int getIDateFromDate(Date date) {
        int year = date.getYear() + 1900;
        int month = date.getMonth() + 1;
        int day = date.getDate();
        return year * 100 * 100 + month * 100 + day;
    }

    @SuppressWarnings("deprecation")
    public static boolean isSameDay(Date dt1, Date dt2) {
        return (dt1.getYear() == dt2.getYear()
                && dt1.getMonth() == dt2.getMonth()
                && dt1.getDate() == dt2.getDate());
    }

    public static int getCurrentIDate() {
        Date currentDate = new Date(System.currentTimeMillis());
        return getIDateFromDate(currentDate);
    }

    @SuppressWarnings("deprecation")
    public static Date getLastTradeDate() {
        long currentMs = System.currentTimeMillis();
        Date openDate = new Date(currentMs);
        while (TradeCalenderRealm.isCloseDay(openDate)) {
            currentMs -= Utils.MILLIS_PER_DAY;
            openDate.setTime(currentMs);
        }
        return openDate;
    }

    @SuppressWarnings("deprecation")
    public static Date geLastCloseDate() {
        long currentMs = System.currentTimeMillis();
        Date currDate = new Date(currentMs);
        while (TradeCalenderRealm.isCloseDay(currDate)) {
            currDate.setTime(currDate.getTime() - Utils.MILLIS_PER_DAY);
        }

        if (currDate.getTime() < currentMs) {
            return currDate;
        }
        if (currDate.getHours() < 18) {
            currDate.setDate(currDate.getDate() - 1);
            currDate.setHours(19);
        }
        return currDate;
    }

    public static Date getCurrentDate() {
        return new Date(System.currentTimeMillis());
    }

//    public static int getLastTradeIDate() {
//        return getIDateFromDate(getLastTradeDate());
//    }

    public static boolean currentTimeIsTrading() {
        long currentMs = System.currentTimeMillis();
        Date currentDate = new Date(currentMs);
        if (TradeCalenderRealm.isCloseDay(currentDate)) {
            return false;
        }
        SimpleDateFormat tickFmt = new SimpleDateFormat("HH:mm:ss", Locale.CHINA);
        String tickString = tickFmt.format(currentDate);
        int iTick = parseTickFromString(tickString);
        return (((iTick > 92500) && (iTick < 113005)) ||
                ((iTick >= 130000) && (iTick < 150005)));
    }

    public static int parseTickFromString(String tickString) {
        String[] dateArray = tickString.split(":");
        return Integer.valueOf(dateArray[0]) * 100 * 100
                + Integer.valueOf(dateArray[1]) * 100
                + Integer.valueOf(dateArray[2]);
    }

    public static String formatStringFromTick(int tick) {
        int hour = tick / 100 / 100;
        int minute = (tick - hour * 100 * 100) / 100;
        int second = tick - hour * 100 * 100 - minute * 100;
        return String.format(Locale.CHINA,
                "%02d:%02d:%02d",
                hour % 100, minute % 100, second % 100);
    }

    public static int minusOfTick(int t1, int t2) {
        int t2h = t2 / 100 / 100;
        int t2m = (t2 - t2h * 100 * 100) / 100;
        int t2s = t2 - t2h * 100 * 100 - t2m * 100;

        int t1h = t1 / 100 / 100;
        int t1m = (t1 - t1h * 100 * 100) / 100;
        int t1s = t1 - t1h * 100 * 100 - t1m * 100;

        return (t2h - t1h) * 60 * 60 + (t2m - t1m) * 60 + (t2s - t1s);
    }

    public static int addSecondToTick(int t1, int seconds) {
        int t1h = t1 / 100 / 100;
        int t1m = (t1 - t1h * 100 * 100) / 100;
        int t1s = t1 - t1h * 100 * 100 - t1m * 100;

        int oSeconds = t1h * 60 * 60 + t1m * 60 + t1s;
        int pSeconds = oSeconds + seconds;
        int ph = pSeconds / 60 / 60;
        int pm = pSeconds / 60 - ph * 60;
        int ps = pSeconds - ph * 60 * 60 - pm * 60;

        return ph * 100 * 100 + pm * 100 + ps;
    }

//    public static String formatIDateStringFromDate(Date date) {
//        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.CHINA);
//        return format.format(date);
//    }

    @SuppressWarnings("deprecation")
    public static boolean isRegularHourDateTime(String date) {
        try {
            Date dt = Utils.sDateMinuteFormat.parse(date);
            int hour = dt.getHours();
            int minute = dt.getMinutes();
            if (hour == 10 && minute == 30)
                return true;
            else if (hour == 11 && minute == 30)
                return true;
            else if (hour == 14 && minute == 0)
                return true;
            else if (hour == 15 && minute == 0)
                return true;
        } catch (ParseException e) {
            return false;
        }
        return false;
    }

    public static Float safeToFloat(String value) {
        Float result = 0.00f;
        if (Utils.isInvalidNumberString(value)) {
            return result;
        }
        try {
            result = Float.parseFloat(value);
        } catch (NumberFormatException e) {
            Log.w(TAG, "Parse (" + value + ") to float error");
        }
        return result;
    }

    public static Integer safeToInteger(String value) {
        int result = 0;
        if (Utils.isInvalidNumberString(value)) {
            return result;
        }
        try {
            result = Integer.valueOf(value);
        } catch (NumberFormatException e) {
            Log.w(TAG, "Parse (" + value + ") to integer error");
        }
        return result;
    }

    public static String buildUrlParameters(Map<String, String> params) {
        StringBuilder sb = new StringBuilder();

        for (Entry<String, String> entry : params.entrySet()) {
            if (sb.length() > 0) {
                sb.append("&");
            }
            String key = entry.getKey();
            String value = entry.getValue();
            try {
                key = URLEncoder.encode(key, "UTF-8");
                value = URLEncoder.encode(value, "UTF-8");
            } catch (UnsupportedEncodingException ex) {
                Log.e(TAG, ex.getMessage(), ex);
                // Still try to continue with unencoded values
            }
            sb.append(String.format("%s=%s", key, value));
        }
        return sb.toString();
    }
//
//
//    public static String unescape(String data) {
//        StringBuilder buffer = new StringBuilder(data.length());
//        for (int i = 0; i < data.length(); i++) {
//            if ((int) data.charAt(i) > 256) {
//                buffer.append("\\u").append(Integer.toHexString((int) data.charAt(i)));
//            } else {
//                if (data.charAt(i) == '\n') {
//                    buffer.append("\\n");
//                } else if (data.charAt(i) == '\t') {
//                    buffer.append("\\t");
//                } else if (data.charAt(i) == '\r') {
//                    buffer.append("\\r");
//                } else if (data.charAt(i) == '\b') {
//                    buffer.append("\\b");
//                } else if (data.charAt(i) == '\f') {
//                    buffer.append("\\f");
//                } else if (data.charAt(i) == '\'') {
//                    buffer.append("\\'");
//                } else if (data.charAt(i) == '\"') {
//                    buffer.append("\\\"");
//                } else if (data.charAt(i) == '\\') {
//                    buffer.append("\\\\");
//                } else {
//                    buffer.append(data.charAt(i));
//                }
//            }
//        }
//        return buffer.toString();
//    }

    public static String volumeToShortUnit(float value) {
        String sign = "";
        value /= 100;
        if (value > 10000 * 10000) {
            value /= 10000 * 10000;
            sign = "亿";
        } else if (value > 10000 * 100) {
            value /= 10000 * 10000;
            sign = "亿";
        } else if (value > 10000) {
            value /= 10000;
            sign = "万";
        }
        BigDecimal b1 = new BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP);
        //return new DecimalFormat("#.00").format(value) + sign;
        return b1.toString() + sign;
    }

    public static String amountToShortUnit(float value) {
        String sign = "";
        if (Math.abs(value) > 10000.0f * 10000 * 10000) {
            value /= 10000.0f * 10000 * 10000;
            sign = "万亿";
        }
//        else if (value > 10000.0f * 10000 * 100) {
//            value /= 10000.0f * 10000 * 100;
//            sign = "百亿";
//        }
        else if (Math.abs(value) > 10000.0f * 10000) {
            value /= 10000 * 10000;
            sign = "亿";
        }
//        else if (value > 10000.0f * 100) {
//            value /= 10000 * 100;
//            sign = "百万";
//        }
        else if (Math.abs(value) > 10000.0f) {
            value /= 10000.0f;
            sign = "万";
        }
        BigDecimal b1 = new BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP);
        //return new DecimalFormat("#.00").format(value) + sign;
        return b1.toString() + sign;
    }

    public static String priceToDecimalString(double price) {
        BigDecimal bd = new BigDecimal(price).setScale(2, BigDecimal.ROUND_HALF_UP);
        return bd.toString();
    }

    public static String percentToDecimalString(double percent) {
        BigDecimal bd = new BigDecimal(percent).setScale(2, BigDecimal.ROUND_HALF_UP);
        return bd.toString() + "%";
    }
//
//    public static int dpToPixels(Context context, int dp) {
//        final float scale = context.getResources().getDisplayMetrics().density;
//        return (int) (dp * scale + 0.5f);
//    }
//
//    public static int spToPixels(Context context, float sp) {
//        final float scale = context.getResources().getDisplayMetrics().scaledDensity;
//        return (int) (sp * scale + 0.5f);
//    }

    private static String neCodeToSymbol(String netEaseCode) {
        String tsCode;
        if (netEaseCode.startsWith("0")) {
            tsCode = "sh" + netEaseCode.substring(1);
        } else {
            tsCode = "sz" + netEaseCode.substring(1);
        }
        return tsCode;
    }

    public static String getTickRealmFile(String netEaseCode, Date tickDate) {
        return neCodeToSymbol(netEaseCode) + "_" + sDefaultDateFormat.format(tickDate) + "_tick.realm";
    }

    private static final String sRealTimeTickRealmSuffix = "rt_tick.realm";
    private static final String sRealTimeTickRealmManageSuffix = "rt_tick.realm.management";
    private static final String sRealTimeTickRealmLockSuffix = "rt_tick.realm.lock";

    public static String getRealTimeTickRealmFile(String netEaseCode, Date tickDate) {
        return neCodeToSymbol(netEaseCode) + "_" + sDefaultDateFormat.format(tickDate) + "_" + sRealTimeTickRealmSuffix;
    }


    private static final String sTodayMinuteTickRealmSuffix = "today_minute_tick.realm";
    private static final String sTodayMinuteTickRealmManageSuffix = "today_minute_tick.realm.management";
    private static final String sTodayMinuteTickRealmLockSuffix = "today_minute_tick.realm.lock";

    public static String getTodayMinuteTickRealmFile(String netEaseCode, Date tickDate) {
        return neCodeToSymbol(netEaseCode) + "_" + sDefaultDateFormat.format(tickDate) + "_" + sTodayMinuteTickRealmSuffix;
    }

    public static String getDayRealmFile(String neCode) {
        return neCodeToSymbol(neCode) + "_day.realm";
    }

    public static String getWeekRealmFile(String neCode) {
        return neCodeToSymbol(neCode) + "_week.realm";
    }

    public static String getMonthRealmFile(String neCode) {
        return neCodeToSymbol(neCode) + "_month.realm";
    }

    public static String getHourRealmFile(String neCode) {
        return neCodeToSymbol(neCode) + "_hour.realm";
    }

    public static List<TickQuote> getTickQuotesFromRealm(String realmFile) {
        List<TickQuote> quoteList = null;
        RealmConfiguration tickRealmConfig = new RealmConfiguration.Builder()
                .name(realmFile)
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(tickRealmConfig);
        RealmResults<TickQuote> results = realm.where(TickQuote.class)
                .sort("tick", Sort.ASCENDING).findAll();
        if (results.size() > 0) {
            quoteList = realm.copyFromRealm(results);
        }
        realm.close();
        return quoteList;
    }

    public static void clearTickQuotesOfRealm(
            String netEaseCode, Date tickDate) {
        RealmConfiguration tickRealmConfig = new RealmConfiguration.Builder()
                .name(Utils.getTickRealmFile(netEaseCode, tickDate))
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(tickRealmConfig);
        realm.beginTransaction();
        realm.deleteAll();
        realm.commitTransaction();
        realm.close();
    }

    public static boolean checkCompleteOfTickDataByDate(
            String netEaseCode, Date tickDate) {
        RealmConfiguration tickRealmConfig = new RealmConfiguration.Builder()
                .name(Utils.getTickRealmFile(netEaseCode, tickDate))
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(tickRealmConfig);
        RealmResults<TickQuote> results = realm.where(TickQuote.class).findAll();
        boolean isComplete = true;
        if (results.size() <= 0) {
            isComplete = false;
        } else {
            Number maxTick = results.max("tick");
            if (maxTick != null) {
                int lastRecordTick = maxTick.intValue();
                if (lastRecordTick < 145000) {
                    // 不完整的历史数据（可能是之前用新浪下的），需要更新
                    isComplete = false;
                }
            }
        }
        realm.close();
        return isComplete;
    }

    public static List<TickQuote> getHistoryTickData(String netEaseCode, Date tickDate) {
        String toastString;
        String tickDayString = sHyphenDateFormat.format(tickDate);
        boolean isComplete =
                checkCompleteOfTickDataByDate(netEaseCode, tickDate);
        if (!isComplete) {
            String errorString =
                    PyTdxHistory.downloadHistoryTickData(
                            netEaseCode, tickDate);
            if (errorString.startsWith("ok")) {
                QuickStockApplication.notifyToast("更新(" +
                        tickDayString + ")分时数据成功(PyTdxHistory)");
            } else {
                toastString = "更新(" + tickDayString + "分时数据失败:"
                        + errorString;
                QuickStockApplication.notifyToast(toastString);
            }
        }

        return Utils.getTickQuotesFromRealm(Utils.getTickRealmFile(netEaseCode, tickDate));
    }

    public static List<KLineChartQuote> loadHourQuotesFromRealm(String netEaseCode, int count) {
        String hourRealmFile = Utils.getHourRealmFile(netEaseCode);
        List<KLineChartQuote> kqList = null;

        RealmConfiguration realmConfig = new RealmConfiguration.Builder()
                .name(hourRealmFile)
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(realmConfig);
        RealmResults<HistoryHourQuote> results =
                realm.where(HistoryHourQuote.class)
                        .sort("date", Sort.ASCENDING).findAll();
        if (results.size() > 0) {
            int start_idx = Math.max(results.size() - count, 0);
            List<HistoryHourQuote> hourList = realm.copyFromRealm(results.subList(start_idx, results.size()));
            kqList = Arrays.asList(hourList.toArray(new KLineChartQuote[0]));
        }
        realm.close();
        return kqList;
    }


    public static List<KLineChartQuote> loadWeekQuotesFromRealm(String netEaseCode, int count) {
        String weekRealmFile = Utils.getWeekRealmFile(netEaseCode);
        List<KLineChartQuote> kqList = null;

        RealmConfiguration realmConfig = new RealmConfiguration.Builder()
                .name(weekRealmFile)
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(realmConfig);
        RealmResults<HistoryWeekQuote> results =
                realm.where(HistoryWeekQuote.class)
                        .sort("date", Sort.ASCENDING).findAll();
        if (results.size() > 0) {
            int start_idx = Math.max(results.size() - count, 0);
            List<HistoryWeekQuote> weekList = realm.copyFromRealm(results.subList(start_idx, results.size()));
            kqList = Arrays.asList(weekList.toArray(new KLineChartQuote[0]));
        }
        realm.close();
        return kqList;
    }

    public static List<KLineChartQuote> loadMonthQuotesFromRealm(String netEaseCode, int count) {
        String monthRealmFile = Utils.getMonthRealmFile(netEaseCode);
        List<KLineChartQuote> kqList = null;

        RealmConfiguration realmConfig = new RealmConfiguration.Builder()
                .name(monthRealmFile)
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(realmConfig);
        RealmResults<HistoryMonthQuote> results =
                realm.where(HistoryMonthQuote.class)
                        .sort("date", Sort.ASCENDING).findAll();
        if (results.size() > 0) {
            int start_idx = Math.max(results.size() - count, 0);
            List<HistoryMonthQuote> monthList = realm.copyFromRealm(results.subList(start_idx, results.size()));
            kqList = Arrays.asList(monthList.toArray(new KLineChartQuote[0]));
        }
        realm.close();
        return kqList;
    }

    public static void preDeleteRealTimeTickRealmFile(String path) {
        File dir = new File(path);
        if (!dir.isDirectory())
            return;
        File[] files = dir.listFiles();
        String lastRTRealm = "_" + sDefaultDateFormat.format(getCurrentDate()) + "_" + sRealTimeTickRealmSuffix;
        String lastRTRealmManage = "_" + sDefaultDateFormat.format(getCurrentDate()) + "_" + sRealTimeTickRealmManageSuffix;
        String lastRTRealmLock = "_" + sDefaultDateFormat.format(getCurrentDate()) + "_" + sRealTimeTickRealmLockSuffix;

        String lastTMRealm = "_" + sDefaultDateFormat.format(getCurrentDate()) + "_" + sTodayMinuteTickRealmSuffix;
        String lastTMRealmManage = "_" + sDefaultDateFormat.format(getCurrentDate()) + "_" + sTodayMinuteTickRealmManageSuffix;
        String lastTMRealmLock = "_" + sDefaultDateFormat.format(getCurrentDate()) + "_" + sTodayMinuteTickRealmLockSuffix;

        long totalSize = 0;
        long totalFiles = 0;
        long bigFiles = 0;
        long bigSize = 0;
        for (File file : files) {
            String fileName = file.getName();
            if ((fileName.endsWith(sRealTimeTickRealmSuffix) && !fileName.endsWith(lastRTRealm)) ||
                    //(fileName.endsWith(sRealTimeTickRealmManageSuffix) && !fileName.endsWith(lastRTRealmManage)) || 这个好像删不掉
                    (fileName.endsWith(sRealTimeTickRealmLockSuffix) && !fileName.endsWith(lastRTRealmLock))
            ) {
                if (!file.delete()) {
                    LogFile.append("RealmUtils", "Fail to delete RealTimeTick Realm:" + fileName);
                }
            } else if ((fileName.endsWith(sTodayMinuteTickRealmSuffix) && !fileName.endsWith(lastTMRealm)) ||
                    // (fileName.endsWith(sTodayMinuteTickRealmManageSuffix) && !fileName.endsWith(lastTMRealmManage)) || || 这个好像删不掉
                    (fileName.endsWith(sTodayMinuteTickRealmLockSuffix) && !fileName.endsWith(lastTMRealmLock))) {
                if (!file.delete()) {
                    LogFile.append("RealmUtils", "Fail to delete TodayMinuteTick Realm:" + fileName);
                }
            } else {
                long fileKSize = file.length() / 1024;
                totalSize += fileKSize;
                totalFiles++;

                if (fileKSize > 100) {
                    bigFiles++;
                    bigSize += fileKSize;
                }
//                LogFile.append("RealmUtils", String.format(Locale.CHINA, "Realm File_%d:%s - %dK", totalFiles, fileName, fileKSize));
            }
        }
        Log.i("RealmUtils", String.format(Locale.CHINA, "Total file Stat:%d - %d M", totalFiles, totalSize / 1024));
        Log.i("RealmUtils", String.format(Locale.CHINA, "Big file Stat:%d - %d M", bigFiles, bigSize / 1024));
    }

//    public static String getFirstPinyinSpell(String chinese) {
//        StringBuffer pybf = new StringBuffer();
//        char[] arr = chinese.toCharArray();
//        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
//        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
//        for (int i = 0; i < arr.length; i++) {
//            if (arr[i] > 128) {
//                try {
//                    String[] temp = PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat);
//                    if (temp != null) {
//                        pybf.append(temp[0].charAt(0));
//                    }
//                } catch (BadHanyuPinyinOutputFormatCombination e) {
//                    e.printStackTrace();
//                }
//            } else {
//                pybf.append(arr[i]);
//            }
//        }
//        return pybf.toString().replaceAll("\\W", "").trim();
//    }

    public static String getFirstPinyinSpell(String chinese) {
        String strPinYin = Pinyin.toPinyin(chinese, ",");
        String[] arrayPinYin = strPinYin.split(",");
        StringBuilder pyjx = new StringBuilder();
        for (String pinyin : arrayPinYin) {
            String head = pinyin.substring(0, 1);
            pyjx.append(head);
        }
        return pyjx.toString();
    }


    public static String toEastMoneyCode(String netEaseCode, boolean isMarketIndex) {
        String emCode;
        if (!isMarketIndex) {
            if (netEaseCode.startsWith("1")) {
                emCode = netEaseCode.substring(1) + "2";
            } else {
                emCode = netEaseCode.substring(1) + "1";
            }
        } else {
            if (netEaseCode.startsWith("1")) {
                emCode = netEaseCode.substring(1) + "1";
            } else {
                emCode = netEaseCode.substring(1) + "2";
            }
        }
        return emCode;
    }

    public static boolean isMainThread() {
        return Looper.getMainLooper().getThread() == Thread.currentThread();
    }

    private static String lastErrorTrace;

    public static synchronized String saveErrorTrace(Exception ex) {
        StringWriter trace = new StringWriter();
        ex.printStackTrace(new PrintWriter(trace));
        lastErrorTrace = trace.toString();
        return lastErrorTrace;
    }

    public static synchronized String getLastErrorTrace() {
        return lastErrorTrace;
    }
//    public static boolean isApplicationDebuggable(Context context) {
//        try {
//            ApplicationInfo info = context.getApplicationInfo();
//            return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
//        } catch (Exception e) {
//            return false;
//        }
//    }

//    public static int getLastTickFromRealm(String netEaseCode, Date tickDate) {
//        RealmConfiguration tickRealmConfig = new RealmConfiguration.Builder()
//                .name(Utils.getTickRealmFile(netEaseCode, tickDate))
//                .deleteRealmIfMigrationNeeded()
//                .build();
//        Realm realm = Realm.getInstance(tickRealmConfig);
//        RealmResults<TickQuote> results = realm.where(TickQuote.class).findAll();
//        int lasTick = -1;
//        if (results.size() > 0) {
//            Number maxTick = results.max("tick");
//            if (maxTick != null)
//                lasTick = maxTick.intValue();
//        }
//        realm.close();
//        return lasTick;
//    }

//    public static boolean isChineseByScript(char c) {
//        Character.UnicodeScript sc = Character.UnicodeScript.of(c);
//        if (sc == Character.UnicodeScript.HAN) {
//            return true;
//        }
//        return false;
//    }

    public static String readFile(String path) {
        try {
            InputStreamReader ins = new InputStreamReader(
                    new FileInputStream(path), StandardCharsets.UTF_8);
            BufferedReader br = new BufferedReader(ins);
            String line;
            StringBuilder builder = new StringBuilder();
            while ((line = br.readLine()) != null) {
                builder.append(line);
            }
            br.close();
            ins.close();
            return builder.toString();
        } catch (Exception e) {
            Log.w(TAG, "loadIndexListByJsonFile error path=" + path, e);
        }
        return "读文件:" + path + "的内容, 失败了。";
    }

    public static void deleteDirectory(File tempFile) {
        try {
            if (!tempFile.exists()) return;
            if (tempFile.isDirectory()) {
                File[] files = tempFile.listFiles();
                if (files == null || files.length == 0) {
                    tempFile.delete();
                    return;
                }
                for (File file : files) {
                    if (file.isFile()) {
                        file.delete();
                    } else if (file.isDirectory()) {
                        deleteDirectory(file);
                    }
                }
                tempFile.delete();
            } else {
                tempFile.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean flushGitRepo(String remoteRepo, String localRepo) {
        try {
            GitHelper.pull(localRepo, null, null, null);
            Log.i(TAG, "Pull " + remoteRepo + " OK");
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Git pull repo:" + remoteRepo + ", Error:", e);
        }

        try {
            File tempFile = new File(localRepo);
            deleteDirectory(tempFile);

            GitHelper.clone(remoteRepo, localRepo, null,
                    null, null);
            Log.i(TAG, "Clone " + remoteRepo + " OK");
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Git clone repo:" + remoteRepo + ",Error:", e);
        }
        QuickStockApplication.notifyToast("刷新" + remoteRepo + "库失败");
        return false;
    }

    public static List<String> getMatchedFiles(String path, String pattern) {
        File file = new File(path);
        if (!file.exists()) {
            return null;
        }
        List<String> matchFiles = new ArrayList<>();
        File[] files = file.listFiles();
        for (File f : files) {
            if (f.getName().equalsIgnoreCase("match_stocks.json"))
                continue;
            if (f.getName().matches(pattern))
                matchFiles.add(f.getName());
        }
        return matchFiles;
    }

    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        if (obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }

    public static String byteArrayToHexString(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            hexString.append(String.format("%02X ", b));
        }
        return hexString.toString();
    }

    public static String tickQuoteListToString(List<TickQuote> tickQuotes) {
        String result = new String();
        for (TickQuote tq : tickQuotes) {
            result += tq.toString();
        }
        return result;
    }

    /**
     * 16进制表示的字符串转换为字节数组
     *
     * @param hexString 16进制表示的字符串
     * @return byte[] 字节数组
     */
    public static byte[] hexStringToByteArray(String hexString) {
        hexString = hexString.replaceAll(" ", "");
        int len = hexString.length();
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个字节
            bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
                    .digit(hexString.charAt(i+1), 16));
        }
        return bytes;
    }

}
